package com.duoec.magichour.invoker.impl;

import com.duoec.magichour.core.CommonConst;
import com.duoec.magichour.core.utils.UUIDUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import java.net.URI;
import java.util.Map;

/**
 * Created by ycoe on 17/7/7.
 */
public class BaseInvoker {
    private static final Logger logger = LoggerFactory.getLogger(BaseInvoker.class);
    private static final String REQUEST_ID = "request-id";

    @Autowired
    private RestTemplate restTemplate;

    public ResponseEntity<String> get(String url) {
        return call(HttpMethod.GET, url, null, null, null, String.class);
    }

    public <R> ResponseEntity<R> get(String url, Class<R> clazz) {
        return call(HttpMethod.GET, url, null, null, null, clazz);
    }

    public ResponseEntity<String> get(String url, Map<String, String> params) {
        return call(HttpMethod.GET, url, params, null, null, String.class);
    }

    public <R> ResponseEntity<R> get(String url, Map<String, String> params, Class<R> clazz) {
        return call(HttpMethod.GET, url, params, null, null, clazz);
    }

    public ResponseEntity<String> get(String url, Map<String, String> params, Map<String, String> headers) {
        return call(HttpMethod.GET, url, params, null, headers, String.class);
    }

    public <R> ResponseEntity<R> get(String url, Map<String, String> params, Map<String, String> headers, Class<R> clazz) {
        return call(HttpMethod.GET, url, params, null, headers, clazz);
    }

    public ResponseEntity<String> post(String url, String body) {
        return call(HttpMethod.POST, url, null, body, null, String.class);
    }

    public <R> ResponseEntity<R> post(String url, Map<String, String> params, String body, Map<String, String> headers, Class<R> clazz) {
        return call(HttpMethod.POST, url, params, body, headers, clazz);
    }

    public <R> ResponseEntity<R> delete(String url, Map<String, String> params, Map<String, String> headers, Class<R> clazz) {
        return call(HttpMethod.DELETE, url, params, null, headers, clazz);
    }

    public <R, B> ResponseEntity<R> call(HttpMethod method, String url, Map<String, String> params, B body, Map<String, String> headers, Class<R> clazz) {
        MultiValueMap<String, String> requestHeaders = new LinkedMultiValueMap();
        if (headers != null && headers.size() > 0) {
            requestHeaders.setAll(headers);
        }
        String requestId = UUIDUtils.generateUUID();
        if (!requestHeaders.containsKey(HttpHeaders.CONTENT_TYPE)) {
            requestHeaders.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
        }
        requestHeaders.add(HttpHeaders.CONTENT_ENCODING, CommonConst.ENCODE);
        requestHeaders.add(REQUEST_ID, requestId);

        UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(url);
        if (params != null && params.size() > 0) {
            for (Map.Entry<String, String> entry : params.entrySet()) {
                uriBuilder.queryParam(entry.getKey(), entry.getValue());
            }
        }

        URI uri = uriBuilder.build().encode().toUri();
        HttpEntity<B> request = new HttpEntity(body, requestHeaders);
        logger.info("[{}]GET: url={}, request={}", requestId, uri, request);
        long start = System.currentTimeMillis();
        ResponseEntity<R> resp = restTemplate.exchange(uri, method, request, clazz);
        logger.info("[{}]GET: url={}, 耗时: {}ms", requestId, uri, System.currentTimeMillis() - start);
        return resp;
    }

}
